package com.esreport.logstash.parser;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.esreport.Utils.HexStringUtil;
import com.esreport.entity.Report;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CityResponse;
import com.maxmind.geoip2.record.Location;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author xuweiwei
 * @date 2018/12/25
 */
@Slf4j
public class QyhlLogParser implements LogParser<Report> {
    private String mmdb;
    private DatabaseReader reader = null;
    private Map<String,GeoPoint> cache = new HashMap<String,GeoPoint>();


    /**
     * 初始化geoip模块
     * @throws IOException
     */
    public void initMethod() throws IOException {
        File database = new File(mmdb);
        reader = new DatabaseReader.Builder(database).build();
    }

    /**
     * 通过ip地址解析经纬度
     * @param ip  ip地址
     * @return 经纬度
     * @throws IOException
     * @throws GeoIp2Exception
     */
    public GeoPoint parseIpAddress(String ip) throws IOException, GeoIp2Exception {
        InetAddress ipAddress = InetAddress.getByName(ip);
        CityResponse response = reader.city(ipAddress);
        Location location = response.getLocation();
        GeoPoint geoPoint = new GeoPoint(location.getLatitude(), location.getLongitude());
        return geoPoint;
    }

    public Date parse(JSONObject jsonObject, String key) {
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
        if (!jsonObject.containsKey(key)) {
            return null;
        }
        String dateStr = jsonObject.getString(key);
        try {
            if (dateStr != null && dateStr.length() > 0) {
                return format1.parse(dateStr);
            }
        } catch (Exception e) {
            log.error(jsonObject.toJSONString());
        }
        return null;
    }

    @Override
    public List<Report> parse(String line) {
        if (!line.contains("[") || !line.contains("]")) {
            return null;
        }
        int pos = line.indexOf(" ");
        if (pos == -1) {
            return null;
        }
        List<Report> reportList = new ArrayList<Report>();
        String ipAddress = line.substring(0, pos);
        GeoPoint location = null;
        try {
            if(cache.containsKey(ipAddress)){
                location = cache.get(ipAddress);
            }else {
                location = parseIpAddress(ipAddress);
                cache.put(ipAddress,location);
            }
        } catch (Exception e) {
            log.error("解析经纬度出错,ip:{}",ipAddress,e);
        }

        //解析json array
        JSONArray jsonArray = null;
        try {
            //json数组
            String jsonArrayStr = line.substring(pos + 1);
            String jsonArrayStrNew = HexStringUtil.hexToString(jsonArrayStr,"UTF-8");
            jsonArray = JSON.parseArray(jsonArrayStrNew);
        } catch (Exception e1) {
            log.error(line);
            return null;
        }
        String seriseSign = UUID.randomUUID().toString().replace("-", "").toLowerCase();
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject) o;
            Date startDate = parse(jsonObject, "startTime");
            Date endDate = parse(jsonObject, "endTime");
            jsonObject.put("id", UUID.randomUUID().toString().replace("-", "").toLowerCase());
            jsonObject.put("startTime", startDate);
            jsonObject.put("endTime", endDate);
            jsonObject.put("seriesSign", seriseSign);
            String phoneType = jsonObject.getString("phoneType");
            if (!StringUtils.isEmpty(phoneType) && !"h5".equals(phoneType) && !"Android".equals(phoneType) && !"IOS".equals(phoneType) && !"MiniProgram".equals(phoneType)) {
                //处理ios日志phoneType和phoneBrand颠倒的bug
                jsonObject.put("phoneType", "IOS");
                jsonObject.put("phoneBrand", phoneType);
                if(jsonObject.containsKey("duration") ){
                    String durationStr = jsonObject.getString("duration");
                    if(durationStr.indexOf(".")>0){
                        float  duration = Float.parseFloat(durationStr);
                        jsonObject.put("duration",Math.floor(duration*1000));
                    }else{
                        int  duration = Integer.parseInt(durationStr);
                        jsonObject.put("duration",duration*1000);
                    }
                }
            }

            Report report = JSON.toJavaObject(jsonObject, Report.class);
            report.setLocation(location);
            report.setIp(ipAddress);
            reportList.add(report);
        }
        return reportList;
    }

    public String getMmdb() {
        return mmdb;
    }

    public void setMmdb(String mmdb) {
        this.mmdb = mmdb;
    }
}
